from ourblockchain.basic import Base
import logging

superID = "00000000-0000-0000-0000-000000000000"


class Block(Base):
    def __init__(self, prev_hash: str = None):
        self.items = []
        self.prev_hash = prev_hash

    def add(self, item):
        # block可能收到来自不同节点的同样的transaction
        if item not in self.items:
            item.prev_hash = self.items[-1].hash() if len(self.items) else None
            self.items.append(item)
        else:
            logging.debug("Duplicate item will be dropped: %s", item)

    def isDoubleOwn(self, item):
        # 一个block中不能存在多个对相同url的own类型购买记录(setPrice也算,因为出现的话也不合理)
        for i in range(len(self.items)):
            tempItem = self.items[i]
            if item.content.url == tempItem.content.url and tempItem.content.purchase_type in ['own', 'setPrice']:
                if item != tempItem:  # 两者不是同个transaction
                    if item.content.purchase_type == 'own':
                        return True
        return False

    def validate(self):
        for i in range(len(self.items)):
            assert i == 0 or self.items[i].prev_hash == self.items[i - 1].hash()
            # 最终验证时也验证下 不存在多次购买同一url
            assert not self.isDoubleOwn(self.items[i])


class Blockchain(Base):
    def __init__(self):
        self.blocks = []

    def add(self, block):
        block.prev_hash = self.blocks[-1].hash() if len(self.blocks) else None
        self.blocks.append(block)

    def validate(self):
        for i in range(len(self.blocks)):
            assert i == 0 or self.blocks[i].prev_hash == self.blocks[i - 1].hash()
            self.blocks[i].validate()

    def find(self, item):
        for block in self.blocks:
            if item in block.items:
                return block.items[block.items.index(item)]


class Ledger(Blockchain):
    # 返回画家卖画的信息
    def getUrlFirstItem(self, url):
        for i in range(len(self.blocks)):
            tempBlock = self.blocks[i]
            for j in range(len(tempBlock.items)):
                tempItem = tempBlock.items[j]
                if tempItem.content.url == url and tempItem.content.purchase_type == 'setPrice':
                    # 图片的第一个买家一定是拍卖行，否则证明数据出错
                    assert tempItem.receiver == superID
                    return tempItem
        return None

    # 返回现拥有者的购买信息
    def getUrlOwnerItem(self, url):
        # 从尾部开始找，最新的own类型的购买记录就是现拥有者
        for i in range(len(self.blocks))[::-1]:
            tempBlock = self.blocks[i]
            for j in range(len(tempBlock.items))[::-1]:
                tempItem = tempBlock.items[j]
                if tempItem.content.url == url and tempItem.content.purchase_type == 'own':
                    return tempItem
        # 画家不算，找不到再通过外部逻辑调用first
        return None

    def ableToTransship(self, url, userId):
        for i in range(len(self.blocks))[::-1]:
            tempBlock = self.blocks[i]
            for j in range(len(tempBlock.items))[::-1]:
                tempItem = tempBlock.items[j]
                if tempItem.content.url == url and tempItem.sender == userId and \
                        tempItem.content.purchase_type == 'transship':
                    return True
        return False

    def balance(self, uuid: str):
        amount = 500
        for i in range(len(self.blocks)):
            tempBlock = self.blocks[i]
            for j in range(len(tempBlock.items)):
                tempItem = tempBlock.items[j]
                if tempItem.sender == uuid:
                    # 画家身份，余额要看这画卖没卖出去
                    if tempItem.content.purchase_type == 'setPrice':
                        ownerItem = self.getUrlOwnerItem(tempItem.content.url)
                        # 卖出去了，就获得定价的钱
                        if ownerItem:
                            amount += tempItem.amount
                    # 买家身份，当买家是sender，花了钱就是花了
                    else:
                        amount -= tempItem.amount
                elif tempItem.receiver == uuid:
                    # 当拍卖行是receiver，拍卖行就只赚画家定价的钱的一定比例的手续费，暂定5%
                    if uuid == superID:
                        # 确定是画家定价的记录
                        if tempItem.content.purchase_type == 'setPrice':
                            ownerItem = self.getUrlOwnerItem(tempItem.content.url)
                            # 卖出去了，就收手续费
                            if ownerItem:
                                amount += int(tempItem.amount * 0.05)
                    # 当receiver是人，收到多少就赚了多少
                    else:
                        amount += tempItem.amount
        return amount

    def ownerChanged(self, transaction):
        # 用于判断transaction要买的url是否已经易主了，如果易主了，那这条transaction也作废了
        owner = self.getUrlOwnerItem(transaction.content.url)
        if owner is None:
            owner = self.getUrlFirstItem(transaction.content.url)
            if owner is None:  # 说明还没有第一条定价的transaction，肯定不算易主
                return False
            else:  # 说明现在由拍卖行托管，所以transaction的receiver不是拍卖行的话就是易主了
                return transaction.receiver != superID
        else:  # transaction的receiver不是现拥有者就是易主了
            return transaction.receiver != owner.sender

    def add(self, block):
        for i in range(len(block.items)):
            tempItem = block.items[i]
            senderUUId = tempItem.sender

            # 定价记录插入检验
            if tempItem.content.purchase_type == 'setPrice':
                firstItem = self.getUrlFirstItem(tempItem.content.url)
                # 必须区块链中不存在该图片且receiver为拍卖行
                assert firstItem is None and tempItem.receiver == superID
            # 非定价记录，就检测余额是否足够就好了
            else:
                balance = self.balance(senderUUId)
                # 超额付款抛异常
                assert tempItem.amount <= balance

        super().add(block)
